/*
 * Copyright 2009 Original Author(s)
 * 
 * This file is part of Kommando
 * 
 * Kommando is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Kommando is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Kommando.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kommando.filesystem.prefs;

import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

import org.kommando.core.controlcenter.PreferencePage;
import org.kommando.filesystem.core.FileSource;
import org.kommando.filesystem.objectsource.FileSystemObjectSource;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;
import ca.odell.glazedlists.impl.beans.BeanTableFormat;
import ca.odell.glazedlists.swing.EventSelectionModel;
import ca.odell.glazedlists.swing.EventTableModel;

/**
 * @author Peter De Bruycker
 */
public class FileSystemPreferencePage implements PreferencePage {

    private JPanel panel;
    private JTable fileSourceTable;

    private EventList<FileSource> fileSources = new BasicEventList<FileSource>();
    private EventList<FileSource> selectedFileSources;

    private FileSystemObjectSource objectSource;

    private Action addAction = new AbstractAction("Add...") {
        {
            putValue(MNEMONIC_KEY, (int) 'a');
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            addFileSource();
        }
    };
    private Action editAction = new AbstractAction("Edit...") {
        {
            setEnabled(false);
            putValue(MNEMONIC_KEY, (int) 'e');
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (!selectedFileSources.isEmpty()) {
                editFileSource(selectedFileSources.get(0));
            }
        }
    };
    private Action duplicateAction = new AbstractAction("Duplicate...") {
        {
            setEnabled(false);
            putValue(MNEMONIC_KEY, (int) 'd');
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (!selectedFileSources.isEmpty()) {
                duplicateFileSource(selectedFileSources.get(0));
            }
        }
    };
    private Action removeAction = new AbstractAction("Remove") {
        {
            setEnabled(false);
            putValue(MNEMONIC_KEY, (int) 'r');
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (!selectedFileSources.isEmpty()) {
                removeFileSource(selectedFileSources.get(0));
            }
        }
    };

    public FileSystemPreferencePage(FileSystemObjectSource objectSource) {
        this.objectSource = objectSource;
    }

    @Override
    public JComponent getComponent() {
        if (panel == null) {
            panel = new JPanel(new MigLayout("wrap 2", // layout constraints
                    "[grow][]", // column constraints
                    "[][grow]")); // row constraints

            JLabel fileSourceTableLabel = new JLabel("File Sources:");
            fileSourceTableLabel.setDisplayedMnemonic('f');
            EventTableModel<FileSource> tableModel = new EventTableModel<FileSource>(fileSources, new BeanTableFormat<FileSource>(FileSource.class,
                    new String[] { "source", "includeSource", "includeHiddenFiles", "depth" }, new String[] { "Source Folder", "Include Source",
                            "Include Hidden", "Depth" }));
            EventSelectionModel<FileSource> selectionModel = new EventSelectionModel<FileSource>(fileSources);
            selectedFileSources = selectionModel.getSelected();
            fileSourceTable = new JTable(tableModel);
            fileSourceTable.setSelectionModel(selectionModel);
            fileSourceTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            fileSourceTableLabel.setLabelFor(fileSourceTable);

            panel.add(fileSourceTableLabel, "span 2");
            panel.add(new JScrollPane(fileSourceTable), "grow");

            JPanel buttons = new JPanel(new MigLayout("insets 0, wrap 1"));

            selectedFileSources.addListEventListener(new ListEventListener<FileSource>() {
                @Override
                public void listChanged(ListEvent<FileSource> e) {
                    updateButtonState(selectedFileSources);
                }
            });

            panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("DELETE"), "remove");
            panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("INSERT"), "add");

            panel.getActionMap().put("remove", removeAction);
            panel.getActionMap().put("add", addAction);

            fileSourceTable.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
                        if (!selectedFileSources.isEmpty()) {
                            editFileSource(selectedFileSources.get(0));
                        }
                    }
                }
            });

            buttons.add(new JButton(addAction), "grow");
            buttons.add(new JButton(duplicateAction), "grow");
            buttons.add(new JButton(editAction), "grow");
            buttons.add(new JButton(removeAction), "grow");

            panel.add(buttons, "top");
        }

        return panel;
    }

    private void updateButtonState(List<FileSource> selection) {
        duplicateAction.setEnabled(selection.size() == 1);
        editAction.setEnabled(selection.size() == 1);
        removeAction.setEnabled(selection.size() == 1);
    }

    @Override
    public boolean apply() {
        for (FileSource deleteThis : new ArrayList<FileSource>(objectSource.getFileSources())) {
            objectSource.removeFileSource(deleteThis);
        }

        for (FileSource addThis : fileSources) {
            objectSource.addFileSource(addThis);
        }

        // TODO save it

        return true;
    }

    @Override
    public void restoreDefaults() {
        // TODO restore defaults
    }

    public void addFileSource() {
        new FileSourceDialog(SwingUtilities.getWindowAncestor(panel)) {
            @Override
            protected void onFinish(FileSource fileSource) {
                fileSources.add(fileSource);
            }
        }.show();
    }

    public void editFileSource(final FileSource oldFileSource) {
        new FileSourceDialog(SwingUtilities.getWindowAncestor(panel)) {
            @Override
            protected void onFinish(FileSource fileSource) {
                fileSources.remove(oldFileSource);
                fileSources.add(fileSource);
            }
        }.show(oldFileSource);
    }

    public void duplicateFileSource(final FileSource fileSource) {
        FileSource duplicate = new FileSource(fileSource.getSource(), fileSource.isIncludeSource(), fileSource.isIncludeHiddenFiles(), fileSource.getDepth(),
                fileSource.getTypes());

        new FileSourceDialog(SwingUtilities.getWindowAncestor(panel)) {
            @Override
            protected void onFinish(FileSource fileSource) {
                fileSources.add(fileSource);
            }
        }.show(duplicate);
    }

    public void removeFileSource(final FileSource fileSource) {
        // TODO ask confirmation
        fileSources.remove(fileSource);
    }

    @Override
    public String getName() {
        return "Files and Folders";
    }

    @Override
    public String getId() {
        return "fileSystem";
    }

    @Override
    public String getParentId() {
        return "catalog";
    }

}
